#include "math_func.h"
// 开尔文温度与摄氏度差值
#define TEMPERATE_TARNS 273.15
/**
 * @desc  : 将NTC热敏电阻的阻值转为温度
 * @date  : 2025-09-26
 * @author: AnRui
 * @param : ref_tmp - {参数说明}: 参考温度,一般是25摄氏度
 * @param : ref_tmp_r - {参数说明}: 热敏电阻在参考温度下的阻值
 * @param : b - {参数说明}: 该型号的热敏电阻的B值
 * @param : cur_r - {参数说明}: 当前的电阻值
 * @return: float
 * @note  : 原公式: Rt = Rp × exp(B × (1/T - 1/T0))
 *          变形:   Tc = [B / (log(Rt/Rp) + B/T0)] - 273.15
 *          Rt:当前电阻值   Rp: 热敏电阻在参考温度下的阻值(欧姆)
 *          B: B值         T0: 参考温度 25℃对应的开尔文温度：273.15+25
 *         -273.15:  将开尔文温度转换为摄氏度
 */
float NTCCalcTemp(float ref_tmp,
    float ref_tmp_r,
    float b,
    float cur_r)
{
    float temp = (b / (log(cur_r / ref_tmp_r) + (b / (TEMPERATE_TARNS + ref_tmp_r)))) - TEMPERATE_TARNS;
    return temp;
}

/**
 * @desc  : 对指定数组生成CRC校验码
 * @date  : 2025-04-21
 * @author: AnRui
 * @param : buf - {参数说明}: 数组指针
 * @param : len - {参数说明}: 数组长度
 * @return: uint8_t
 * @note  :
 */
uint8_t MathCalcCrc8(uint8_t* buf, uint32_t len)
{
    uint8_t crc = 0xFF;
    for (uint8_t byte = 0; byte < len; byte++) {
        crc ^= (buf[byte]);
        for (uint8_t i = 8; i > 0; --i) {
            if (crc & 0x80) {
                crc = (crc << 1) ^ 0x31;
            } else {
                crc = (crc << 1);
            }
        }
    }
    return crc;

}
/**
 * @desc  : 对数组计算算术平均值
 * @date  : 2025-04-07
 * @author: AnRui
 * @param : arr - {参数说明}: 数组
 * @param : len - {参数说明}: 数组长度
 * @return: uint16_t
 * @note  : 数组元素类型要求是uint16_t
 */
uint16_t MathCalcArithmeticMean(const uint16_t* arr, uint32_t len)
{
    uint32_t sum = 0;
    for (uint32_t i = 0; i < len; i++) {
        sum += arr[i];
    }
    return (uint16_t)(sum / len);
}

/**
 * @desc  : 升序比较
 * @date  : 2025-04-08
 * @author: AnRui
 * @param : _a - {参数说明}: 元素
 * @param : _b - {参数说明}: 元素
 * @return: int32_t
 * @note  : 数组元素类型要求是uint16_t
 */
static int32_t CompareAscending(const void* _a, const void* _b)
{
    uint16_t* a = (uint16_t*)_a;
    uint16_t* b = (uint16_t*)_b;
    int32_t val = 0;
    if (*a > *b) {
        val = 1;
    } else if (*a < *b) {
        val = -1;
    } else {
        val = 0;
    }
    return val;
}


/**
 * @desc  : 降序比较
 * @date  : 2025-04-08
 * @author: AnRui
 * @param : _a - {参数说明}: 元素
 * @param : _b - {参数说明}: 元素
 * @return: int32_t
 * @note  :
 */
static int32_t CompareDescending(const void* _a, const void* _b)
{
    return -CompareAscending(_a, _b);
}

/**
 * @desc  : 对数组进行升序|降序排序
 * @date  : 2025-04-08
 * @author: AnRui
 * @param : arr - {参数说明}: 数组
 * @param : arrLen - {参数说明}: 数组长度
 * @param : direction - {参数说明}: 排序方向: 1:升序  -1:降序
 * @note  : 数组元素类型要求是uint16_t
 */
void SortArrayByDirection(uint16_t* arr, uint32_t arrLen, int direction)
{
    switch (direction) {
    case 1:
        qsort(arr, arrLen, sizeof(uint16_t), CompareAscending);
        return;
    case -1:
        qsort(arr, arrLen, sizeof(uint16_t), CompareDescending);
        return;
    default:
        return;
    }
}


/**
 * @desc  : 对数组进行去掉极值的中位数计算
 * @date  : 2025-04-08
 * @author: AnRui
 * @param : arr - {参数说明}: 数组指针
 * @param : len - {参数说明}: 数组长度
 * @return: uint16_t
 * @note  : 1.数组元素为uint16_t类型 2.数组元素必须>=3 3.数组元素类型要求是uint16_t
 */
uint16_t MathCalcTrimmedMean(uint16_t* arr, uint32_t len)
{
    if (len < 3) { return 0; }
    qsort(arr, len, sizeof(uint16_t), CompareAscending);
    return MathCalcArithmeticMean(&arr[1], len - 2);
}


/**
 * @desc  : 在升序数组中基于二分法查找对应元素的下标
 * @date  : 2025-04-08
 * @author: AnRui
 * @param : arr - {参数说明}:  数组指针
 * @param : size - {参数说明}: 数组长度
 * @param : key - {参数说明}:  查找的值
 * @return: int32_t
 * @note  : 数组的数据类型为uint16_t
 */
int32_t MathCalcAsecBinarySearch(const uint16_t* arr, int32_t size, uint16_t key)
{
    int32_t left = 0;              			//设置左下标
    int32_t right = size - 1;       			//设置右下标
    int32_t mid;
    while (left <= right)                   //循环终止条件: left == right + 1，搜索区间为空，终止循环
    {
        mid = left + (right - left) / 2;  	//设置中间下标，防止(left + right)溢出
        if (key < arr[mid])           	               //如果指定元素比中间下标的值小
            right = mid - 1;            	//则把中间下标-1给右下标
        else if (key > arr[mid])      	//如果指定元素比中间下标的值大
            left = mid + 1;             	//则把中间下标+1给左下标
        else                         		//否则返回 中间下标
            return mid;
    }
    return -1;               			//返回-1则表示在该数组中未找到该指定元素
}


/**
 * @desc  : 在降序数组中基于二分法查找对应元素的下标
 * @date  : 2025-04-08
 * @author: AnRui
 * @param : arr - {参数说明}:  数组指针
 * @param : size - {参数说明}: 数组长度
 * @param : key - {参数说明}:  查找的值
 * @return: int32_t
 * @note  : 数组的数据类型为uint16_t
 */
int32_t MathCalcDescBinarySearch(const uint16_t* arr, int32_t size, uint16_t key)
{
    int32_t left = 0;              			//设置左下标
    int32_t right = size - 1;       			//设置右下标
    int32_t mid;
    while (left <= right)             //循环终止条件: left == right + 1，搜索区间为空，终止循环
    {
        mid = left + (right - left) / 2;  	//设置中间下标，防止(left + right)溢出
        if (key > arr[mid])           	               //如果指定元素比中间下标的值大
            right = mid - 1;            	//则把中间下标-1给右下标
        else if (key < arr[mid])      	//如果指定元素比中间下标的值小
            left = mid + 1;             	//则把中间下标+1给左下标
        else                         		//否则返回 中间下标
            return mid;
    }
    return -1;               			//返回-1则表示在该数组中未找到该指定元素
}


/**
 * @desc  : 基于二分查找法 在升序数组中查找最接近目标值的元素
 * @date  : 2025-04-08
 * @author: AnRui
 * @param : arr - {参数说明}:
 * @param : size - {参数说明}:
 * @param : key - {参数说明}:
 * @return: int32_t
 * @note  : 1.数组元素必须是升序排列 2.查出来的元素是大于等于目标值的,即便有小于目标值的元素更接近,也不采用
 */
int32_t  MathCalcAscBinarySearchNear(const uint16_t* arr, int32_t size, uint16_t key)
{
    int32_t left = 0;
    int32_t right = size - 1;
    int32_t mid;
    int32_t index = size - 1;
    while (left <= right) {
        mid = left + (right - left) / 2;
        if (key <= arr[mid]) {
            right = mid - 1;
            index = mid;
        } else {
            left = mid + 1;
        }
    }
    return index;
}



/**
 * @desc  : 基于二分查找法 在降序数组中查找最接近目标值的元素
 * @date  : 2025-04-08
 * @author: AnRui
 * @param : arr - {参数说明}:
 * @param : size - {参数说明}:
 * @param : key - {参数说明}:
 * @return: int32_t
 * @note  : 1.数组元素必须是降序排列 2.查出来的元素是小于等于目标值的,即便有大于目标值的元素更接近,也不采用
 */
int32_t MathCalcDescBinarySearchNear(const uint16_t* arr, int32_t size, uint16_t key)
{
    int32_t left = 0;
    int32_t right = size - 1;
    int32_t mid;
    int32_t index = size - 1;
    while (left <= right) {
        mid = left + (right - left) / 2;
        if (key >= arr[mid]) {
            right = mid - 1;
            index = mid;
        } else {
            left = mid + 1;
        }
    }
    return index;
}

/**
 * @desc  : 16进制的uint8类型数据转为二进制打印
 * @date  : 2025-10-07
 * @author: AnRui
 * @param : hex_data - {参数说明}:
 * @note  :
 */
void hex_to_binary_print(uint8_t hex_data)
{
    char buff[9] = { 0 };
    for (int i = 0;i < 8;i++) {
        buff[7 - i] = "01"[hex_data % 2];
        hex_data /= 2;
    }
    printf("ob%s\r\n", buff);
}


/**
 * @desc  : 获取int类型的数据 第几位的值
 * @date  : 2025-10-08
 * @author: AnRui
 * @param : target - {参数说明}:目标值
 * @param : index - {参数说明}: 位置从0开始
 * @return: int
 * @note  :
 */
int get_digit_by_position(int target, int index)
{
    int power = 1, i;
    for (i = 1; i <= index; i++) {
        power *= 10;
    }
    return target / power % 10;
}